package com.hwpt.hwaccount.core.utils;

import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * Bean属性拷贝工具类
 * 类似Spring Framework的BeanUtils.copyProperties方法
 */
public class BeanUtils {
    private static final String TAG = "BeanUtils";

    /**
     * 拷贝源对象属性到目标对象
     * @param source 源对象
     * @param target 目标对象
     */
    public static void copyProperties(Object source, Object target) {
        copyProperties(source, target, (String[]) null);
    }

    /**
     * 拷贝源对象属性到目标对象，可忽略指定属性
     * @param source 源对象
     * @param target 目标对象
     * @param ignoreProperties 要忽略的属性名数组
     */
    public static void copyProperties(Object source, Object target, String... ignoreProperties) {
        if (source == null || target == null) {
            Log.w(TAG, "Source or target object is null");
            return;
        }

        // 处理忽略的属性
        Set<String> ignoreSet = new HashSet<>();
        if (ignoreProperties != null) {
            ignoreSet.addAll(Arrays.asList(ignoreProperties));
        }

        Class<?> sourceClass = source.getClass();
        Class<?> targetClass = target.getClass();

        // 获取目标类的所有方法
        Method[] methods = targetClass.getMethods();
        
        for (Method setter : methods) {
            if (isSetterMethod(setter)) {
                String propertyName = getPropertyNameFromSetter(setter);
                
                // 检查是否在忽略列表中
                if (ignoreSet.contains(propertyName)) {
                    continue;
                }

                try {
                    // 获取对应的getter方法
                    Method getter = getGetterMethod(sourceClass, propertyName, setter.getParameterTypes()[0]);
                    if (getter != null) {
                        Object value = getter.invoke(source);
                        // 只拷贝非空值，如果需要拷贝null值可以移除这个判断
                        if (value != null) {
                            setter.invoke(target, value);
                        }
                    }
                } catch (Exception e) {
                    Log.d(TAG, "Property " + propertyName + " copy failed: " + e.getMessage());
                    // 忽略找不到对应getter或类型不匹配的情况
                }
            }
        }
    }

    /**
     * 使用反射方式拷贝属性（更彻底的拷贝，包括私有字段）
     */
    public static void copyPropertiesReflect(Object source, Object target, String... ignoreProperties) {
        if (source == null || target == null) {
            return;
        }

        Set<String> ignoreSet = new HashSet<>();
        if (ignoreProperties != null) {
            ignoreSet.addAll(Arrays.asList(ignoreProperties));
        }

        Field[] sourceFields = source.getClass().getDeclaredFields();
        Field[] targetFields = target.getClass().getDeclaredFields();

        for (Field sourceField : sourceFields) {
            String fieldName = sourceField.getName();
            
            if (ignoreSet.contains(fieldName)) {
                continue;
            }

            try {
                sourceField.setAccessible(true);
                Object value = sourceField.get(source);

                // 查找目标类中的对应字段
                for (Field targetField : targetFields) {
                    if (targetField.getName().equals(fieldName) && 
                        isAssignable(targetField.getType(), sourceField.getType())) {
                        targetField.setAccessible(true);
                        targetField.set(target, value);
                        break;
                    }
                }
            } catch (Exception e) {
                Log.d(TAG, "Field " + fieldName + " copy failed: " + e.getMessage());
            }
        }
    }

    /**
     * 判断是否是setter方法
     */
    private static boolean isSetterMethod(Method method) {
        return method.getName().startsWith("set") && 
               method.getParameterTypes().length == 1 &&
               method.getReturnType().equals(void.class);
    }

    /**
     * 从setter方法获取属性名
     */
    private static String getPropertyNameFromSetter(Method setter) {
        String methodName = setter.getName();
        if (methodName.startsWith("set") && methodName.length() > 3) {
            String fieldName = methodName.substring(3);
            return fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
        }
        return "";
    }

    /**
     * 获取对应的getter方法
     */
    private static Method getGetterMethod(Class<?> clazz, String propertyName, Class<?> parameterType) {
        String getterName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        String isName = "is" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        
        try {
            // 先尝试getXxx方法
            return clazz.getMethod(getterName);
        } catch (NoSuchMethodException e1) {
            try {
                // 再尝试isXxx方法（用于boolean类型）
                Method isMethod = clazz.getMethod(isName);
                if (isMethod.getReturnType().equals(Boolean.class) || 
                    isMethod.getReturnType().equals(boolean.class)) {
                    return isMethod;
                }
            } catch (NoSuchMethodException e2) {
                // 两个方法都不存在
            }
        }
        return null;
    }

    /**
     * 检查类型是否可赋值
     */
    private static boolean isAssignable(Class<?> targetType, Class<?> sourceType) {
        if (targetType.isAssignableFrom(sourceType)) {
            return true;
        }
        
        // 处理基本类型和包装类型的兼容性
        if (targetType.isPrimitive()) {
            return getWrapperType(targetType).equals(sourceType);
        } else if (sourceType.isPrimitive()) {
            return targetType.equals(getWrapperType(sourceType));
        }
        
        return false;
    }

    /**
     * 获取基本类型的包装类型
     */
    private static Class<?> getWrapperType(Class<?> primitiveType) {
        if (primitiveType == int.class) return Integer.class;
        if (primitiveType == long.class) return Long.class;
        if (primitiveType == double.class) return Double.class;
        if (primitiveType == float.class) return Float.class;
        if (primitiveType == boolean.class) return Boolean.class;
        if (primitiveType == byte.class) return Byte.class;
        if (primitiveType == short.class) return Short.class;
        if (primitiveType == char.class) return Character.class;
        return primitiveType;
    }

    /**
     * 拷贝属性并返回目标对象（方便链式调用）
     */
    public static <T> T copyProperties(Object source, Class<T> targetClass) {
        try {
            T target = targetClass.newInstance();
            copyProperties(source, target);
            return target;
        } catch (Exception e) {
            Log.e(TAG, "Create target instance failed: " + e.getMessage());
            return null;
        }
    }

    /**
     * 拷贝属性并返回目标对象（带忽略属性）
     */
    public static <T> T copyProperties(Object source, Class<T> targetClass, String... ignoreProperties) {
        try {
            T target = targetClass.newInstance();
            copyProperties(source, target, ignoreProperties);
            return target;
        } catch (Exception e) {
            Log.e(TAG, "Create target instance failed: " + e.getMessage());
            return null;
        }
    }
}